package com.hra.logger;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.provider.Settings;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.hra.logger.utils.LogFactory;
import com.hra.logger.utils.Utils;

@SuppressWarnings("all")
public class MainActivity extends AppCompatActivity {

    private LoggingService loggingService;
    private boolean isServiceBound = false;

    static final SparseIntArray KEY_LOG_CONTAINER_ID_MAP = new SparseIntArray();

    static {
        KEY_LOG_CONTAINER_ID_MAP.put(Utils.LOG_TYPE_KERNEL, R.id.kernelLogContainer);
        KEY_LOG_CONTAINER_ID_MAP.put(Utils.LOG_TYPE_MAIN, R.id.mainLogContainer);
        KEY_LOG_CONTAINER_ID_MAP.put(Utils.LOG_TYPE_SYSTEM, R.id.systemLogContainer);
        KEY_LOG_CONTAINER_ID_MAP.put(Utils.LOG_TYPE_CRASH, R.id.crashLogContainer);
        KEY_LOG_CONTAINER_ID_MAP.put(Utils.LOG_TYPE_RADIO, R.id.radioLogContainer);
        KEY_LOG_CONTAINER_ID_MAP.put(Utils.LOG_TYPE_EVENTS, R.id.eventsLogContainer);
    }

    static final SparseIntArray KEY_LOG_SWITCH_ID_MAP = new SparseIntArray();

    static {
        KEY_LOG_SWITCH_ID_MAP.put(Utils.LOG_TYPE_KERNEL, R.id.kernelLogStartStopSwitch);
        KEY_LOG_SWITCH_ID_MAP.put(Utils.LOG_TYPE_MAIN, R.id.mainLogStartStopSwitch);
        KEY_LOG_SWITCH_ID_MAP.put(Utils.LOG_TYPE_SYSTEM, R.id.systemLogStartStopSwitch);
        KEY_LOG_SWITCH_ID_MAP.put(Utils.LOG_TYPE_CRASH, R.id.crashLogStartStopSwitch);
        KEY_LOG_SWITCH_ID_MAP.put(Utils.LOG_TYPE_RADIO, R.id.radioLogStartStopSwitch);
        KEY_LOG_SWITCH_ID_MAP.put(Utils.LOG_TYPE_EVENTS, R.id.eventsLogStartStopSwitch);
    }

    static final SparseIntArray KEY_LOG_TEXT_VIEW_ID_MAP = new SparseIntArray();

    static {
        KEY_LOG_TEXT_VIEW_ID_MAP.put(Utils.LOG_TYPE_KERNEL, R.id.kernelLogTextView);
        KEY_LOG_TEXT_VIEW_ID_MAP.put(Utils.LOG_TYPE_MAIN, R.id.mainLogTextView);
        KEY_LOG_TEXT_VIEW_ID_MAP.put(Utils.LOG_TYPE_SYSTEM, R.id.systemLogTextView);
        KEY_LOG_TEXT_VIEW_ID_MAP.put(Utils.LOG_TYPE_CRASH, R.id.crashLogTextView);
        KEY_LOG_TEXT_VIEW_ID_MAP.put(Utils.LOG_TYPE_RADIO, R.id.radioLogTextView);
        KEY_LOG_TEXT_VIEW_ID_MAP.put(Utils.LOG_TYPE_EVENTS, R.id.eventsLogTextView);
    }

    private final SparseArray<TypeLogLayout> mTypeLogLayout = new SparseArray<>();

    private CompoundButton switchAll;
    private ImageButton btnOpenCleaner;
    private TextView timeTv;

    private CompoundButton.OnCheckedChangeListener masterListener;

    private final ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            LoggingService.LocalBinder binder = (LoggingService.LocalBinder) service;
            loggingService = binder.getService();
            isServiceBound = true;
            updateUIFromService();
            if (loggingService != null) {
                loggingService.registerTimerCallback(formattedTime -> {
                    runOnUiThread(() -> {
                        if (timeTv != null) {
                            timeTv.setText(formattedTime);
                        }
                    });
                });
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            if (loggingService != null) {
                loggingService.registerTimerCallback(null);
            }
            isServiceBound = false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (!Environment.isExternalStorageManager()) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
            intent.addCategory("android.intent.category.DEFAULT");
            intent.setData(Uri.parse(String.format("package:%s", getApplicationContext().getPackageName())));
            startActivityForResult(intent, 1001);
        }

        // initViews
        TextView tips = findViewById(R.id.tip_text_view);
        tips.setText(getString(R.string.log_storage_location, Utils.LOG_PATH));
        timeTv = findViewById(R.id.tv_time);
        switchAll = findViewById(R.id.switch_all);
        btnOpenCleaner = findViewById(R.id.clearLogImageButton);
        btnOpenCleaner.setOnClickListener(v -> {
            startActivity(new Intent(this, LogCleanerActivity.class));
        });
        for (int logType : Utils.LOG_TYPES) {
            mTypeLogLayout.put(logType, new TypeLogLayout(logType));
        }

        setupSwitchListeners();

        Intent serviceIntent = new Intent(this, LoggingService.class);
        startForegroundService(serviceIntent);
        bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    private void setupSwitchListeners() {
        // Main switch
        masterListener = (buttonView, isChecked) -> {
            if (!isServiceBound) return;
            btnOpenCleaner.setEnabled(!isChecked);
            if (isChecked) {
                // Open all logs
                for (int logType : Utils.LOG_TYPES) {
                    loggingService.startLogging(logType);
                    TypeLogLayout layout = mTypeLogLayout.get(logType);
                    if (layout != null) {
                        layout.mLogStartStopSwitch.setChecked(true);
                        layout.mLogStatusTextView.setText(getString(R.string.log_start, Utils.getLogTypeName(logType)));
                    }
                }
            } else {
                // Stop all logs
                loggingService.stopAllLogging();
                for (int i = 0; i < mTypeLogLayout.size(); i++) {
                    TypeLogLayout layout = mTypeLogLayout.valueAt(i);
                    if (layout != null) {
                        layout.mLogStartStopSwitch.setChecked(false);
                        layout.mLogStatusTextView.setText(getString(R.string.log_stop, Utils.getLogTypeName(mTypeLogLayout.keyAt(i))));
                    }
                }
            }
        };
        switchAll.setOnCheckedChangeListener(masterListener);

        // sub switch
        for (int logType : Utils.LOG_TYPES) {
            TypeLogLayout layout = mTypeLogLayout.get(logType);
            if (layout == null || layout.mLogStartStopSwitch == null) continue;

            layout.mLogStartStopSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
                if (!isServiceBound) return;
                if (isChecked) {
                    loggingService.startLogging(logType);
                } else {
                    loggingService.stopLogging(logType);
                }
                layout.mLogStatusTextView.setText(getString(isChecked ? R.string.log_start : R.string.log_stop, Utils.getLogTypeName(logType)));
                updateMasterSwitchState();
            });
        }
    }

    private void updateUIFromService() {
        if (!isServiceBound) return;
        // Update all switch statuses
        for (int logType : Utils.LOG_TYPES) {
            boolean isActive = loggingService.isLoggingActive(logType);
            TypeLogLayout layout = mTypeLogLayout.get(logType);
            if (layout != null && layout.mLogStartStopSwitch != null) {
                layout.mLogStartStopSwitch.setChecked(isActive);
                layout.mLogStatusTextView.setText(getString(isActive ? R.string.log_start : R.string.log_stop, Utils.getLogTypeName(logType)));
            }
        }
        updateMasterSwitchState();
        updateLayoutVisible();
    }

    // Only update the status of the main switch, without triggering the listener
    private void updateMasterSwitchState() {
        if (!isServiceBound) return;
        // Check if any sub switches are turned on
        boolean anyActive = false;
        for (int logType : Utils.LOG_TYPES) {
            if (loggingService.isLoggingActive(logType)) {
                anyActive = true;
                break;
            }
        }
        // Temporary removal of listener to prevent recursion
        switchAll.setOnCheckedChangeListener(null);
        switchAll.setChecked(anyActive);
        switchAll.setOnCheckedChangeListener(masterListener);
        btnOpenCleaner.setEnabled(!anyActive);
    }

    private void updateLayoutVisible() {
        try {
            boolean anyVisible = false;
            for (int logType : Utils.LOG_TYPES) {
                TypeLogLayout layout = mTypeLogLayout.get(logType);
                if (layout == null) continue;
                if (LogFactory.getLogCollector(logType) != null) {
                    boolean visible = LogFactory.getLogCollector(logType).isVisible();
                    if (visible) {
                        anyVisible = true;
                    }
                    layout.mLogContainer.setVisibility(visible ? View.VISIBLE : View.GONE);
                }
            }
            findViewById(R.id.switch_divider).setVisibility(anyVisible ? View.VISIBLE : View.GONE);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (isServiceBound) {
            unbindService(serviceConnection);
            isServiceBound = false;
        }
    }

    class TypeLogLayout {
        LinearLayout mLogContainer;
        CompoundButton mLogStartStopSwitch;
        TextView mLogStatusTextView;
        int mLogType = 0;

        public TypeLogLayout(int logType) {
            this.mLogType = logType;
            mLogContainer = findViewById(KEY_LOG_CONTAINER_ID_MAP.get(logType));
            mLogStartStopSwitch = findViewById(KEY_LOG_SWITCH_ID_MAP.get(logType));
            mLogStatusTextView = findViewById(KEY_LOG_TEXT_VIEW_ID_MAP.get(logType));
            mLogStatusTextView.setText(getString(R.string.log_stop, Utils.getLogTypeName(logType)));
        }
    }
}